package org.jeecg.modules.htxincailiao.industry.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.util.SmartBeanUtil;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.htxincailiao.industry.constant.HTCheckConstant;
import org.jeecg.modules.htxincailiao.industry.domain.bo.HTIndustryApplyBO;
import org.jeecg.modules.htxincailiao.industry.domain.dto.HTIndustrySalonApplyDTO;
import org.jeecg.modules.htxincailiao.industry.entity.HTIndustrySalon;
import org.jeecg.modules.htxincailiao.industry.entity.HTIndustrySalonApply;
import org.jeecg.modules.htxincailiao.industry.entity.HTIndustrySalonCheck;
import org.jeecg.modules.htxincailiao.industry.mapper.HTIndustrySalonApplyMapper;
import org.jeecg.modules.htxincailiao.industry.service.IHTIndustrySalonApplyService;
import org.jeecg.modules.htxincailiao.industry.service.IHTIndustrySalonCheckService;
import org.jeecg.modules.htxincailiao.industry.service.IHTIndustrySalonService;
import org.jeecg.modules.htxincailiao.order.constant.HTOrderTypeEnum;
import org.jeecg.modules.htxincailiao.order.domain.bo.HTIndustryOrderCreateBO;
import org.jeecg.modules.htxincailiao.order.domain.vo.HTSubmitOrderVO;
import org.jeecg.modules.htxincailiao.order.service.IHTOrderService;
import org.jeecg.modules.htxincailiao.payment.entity.HTPayment;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.transaction.Transactional;

/**
 * @Description: ht_industry_salon_apply
 * @Author: jeecg-boot
 * @Date: 2021-06-05
 * @Version: V1.0
 */
@Service
public class HTIndustrySalonApplyServiceImpl extends ServiceImpl<HTIndustrySalonApplyMapper, HTIndustrySalonApply> implements IHTIndustrySalonApplyService {

    @Resource
    private IHTIndustrySalonService industrySalonService;

    @Resource
    private IHTIndustrySalonCheckService industrySalonCheckService;

    @Resource
    private IHTOrderService orderService;

    @Override
    public HTIndustrySalonApply queryBySalonId(String salonId) {
        return baseMapper.queryBySalonId(salonId);
    }

    @Override
    public HTIndustrySalonApply queryBy(String userId, String salonId, Integer applyObjectType) {
        return baseMapper.queryBy(userId, salonId, applyObjectType);
    }

    @Override
    @Transactional
    public HTIndustryApplyBO handleUserApply(HTIndustrySalonApplyDTO dto, String userId) {
        HTIndustryApplyBO bo = new HTIndustryApplyBO();
        HTIndustrySalonApply salonApply = SmartBeanUtil.copy(dto, HTIndustrySalonApply.class);
        assert salonApply != null;
        HTIndustrySalon salon = industrySalonService.getById(dto.getSalonId());

        salonApply.setApplyUserId(userId);
        salonApply.setSalonId(salon.getId());

        System.out.printf("\n\n\n salonApply %s \n\n\n", JSONObject.toJSONString(salonApply));

        try {
            boolean success = save(salonApply);
            bo.setSuccess(success);
        } catch (Exception e) {
            throw new JeecgBootException("创建报名记录失败");
        }

        boolean needPayment = getNeedPayment(dto, salon);
        if (needPayment) {
            HTPayment paymentItem = handlePaymentSalon(dto, salon, salonApply);
            bo.setPaymentItem(paymentItem);
        } else {
            bo.setSuccess(handleFeeSalon(dto, userId, salonApply));
        }

        return bo;
    }

    private boolean handleFeeSalon(HTIndustrySalonApplyDTO dto, String userId, HTIndustrySalonApply salonApply) {
        boolean success = false;

        //观展用户才创建签到记录
        if (dto.getApplyObjectType() == 1) {
            HTIndustrySalonCheck check = createCheck(salonApply, userId);
            try {
                success = industrySalonCheckService.save(check);
            } catch (Exception e) {
                throw new JeecgBootException("创建签到记录失败");
            }

            try {
                //免费默认1张 现场自动签到
                salonApply.setQuantity(1);
                success = updateById(salonApply);
            } catch (Exception e) {
                throw new JeecgBootException("创建签到记录失败");
            }
        } else {
            success = true;
        }

        return success;
    }

    private HTIndustrySalonCheck createCheck(HTIndustrySalonApply salonApply, String userId) {
        HTIndustrySalonCheck check = new HTIndustrySalonCheck();
        check.setSalonId(salonApply.getSalonId());
        check.setBuyerId(userId);
        return check;
    }

    private boolean handlePaymentSalonCheck(HTIndustrySalonApply salonApply) {
        boolean success = false;
        //观展用户才创建签到记录
        if (salonApply.getApplyObjectType() == 1) {
            if (oConvertUtils.isNotEmpty(salonApply.getQuantity()) && salonApply.getQuantity() > 0) {
                if (salonApply.getQuantity() > salonApply.getLimitQuantityPerUser()) {
                    String message = "每人限购" + salonApply.getLimitQuantityPerUser() + "张";
                    throw new JeecgBootException(message);
                }

                for (int i = 0; i < salonApply.getQuantity(); i++) {
                    String code = getCode(salonApply.getSalonId());
                    if (oConvertUtils.isNotEmpty(code)) {
                        HTIndustrySalonCheck check = createCheck(salonApply, salonApply.getApplyUserId());
                        check.setCode(code);
                        success = industrySalonCheckService.save(check);
                    } else {
                        throw new JeecgBootException("创建入场码失败");
                    }
                }
            } else {
                throw new JeecgBootException("购买数量不能为空且必须大于0");
            }
        } else {
            success = true;
        }
        return success;
    }

    private HTPayment handlePaymentSalon(HTIndustrySalonApplyDTO dto, HTIndustrySalon salon,
                                              HTIndustrySalonApply salonApply) {
        HTPayment paymentItem = null;
        boolean checkSaveSuccess = handlePaymentSalonCheck(salonApply);
        if (checkSaveSuccess) {
            HTIndustryOrderCreateBO orderBO = SmartBeanUtil.copy(dto, HTIndustryOrderCreateBO.class);
            assert orderBO != null;
            orderBO.setBuyerId(salonApply.getApplyUserId());
            orderBO.setOrderType(HTOrderTypeEnum.INDUSTRY_SALON);
            if (salonApply.getApplyObjectType() == 0) {
                String name = salon.getName() + " - 展商报名费";
                orderBO.setName(name);
            } else if (salonApply.getApplyObjectType() == 1) {
                String name = salon.getName() + " - 观众报名费";
                orderBO.setName(name);
            }

            HTSubmitOrderVO submitOrderVO = orderService.createOrderForIndustry(orderBO);
            paymentItem = submitOrderVO.getPayment();

            if (oConvertUtils.isNotEmpty(paymentItem) && oConvertUtils.isNotEmpty(paymentItem.getOrderId())) {
                salonApply.setOrderId(paymentItem.getOrderId());
                try {
                    updateById(salonApply);
                } catch (Exception e) {
                    throw new JeecgBootException("更新报名记录失败");
                }
            }
        }

        return paymentItem;
    }

    private boolean getNeedPayment(HTIndustrySalonApplyDTO dto, HTIndustrySalon salon) {
        boolean needPayment = false;
        Integer applyObjectType = dto.getApplyObjectType();
        if (applyObjectType == 0) {
            needPayment = oConvertUtils.isNotEmpty(salon.getExhibitorCost()) && salon.getExhibitorCost().floatValue() > 0;
        } else if (applyObjectType == 1) {
            needPayment = oConvertUtils.isNotEmpty(salon.getAudienceCost()) && salon.getAudienceCost().floatValue() > 0;
        }

        return needPayment;
    }

    private String getCode(String salonId) {
        // 入场码 剔除0oO1lL
        String code = RandomUtil.randomStringWithoutStr(HTCheckConstant.CODE_LENGTH, "0oO1lL");
        HTIndustrySalonCheck storedCheck = industrySalonCheckService.queryByCode(salonId, code);
        Integer tryCount = HTCheckConstant.CODE_REGENERATE_TRY_COUNT;
        // 优化方案：提前把Code生成到一个缓存池，用的时候直接取
        // 如果入场码重复则重新尝试CODE_REGENERATE_TRY_COUNT次生成新的入场码，如果还是失败则返回前端错误
        while (oConvertUtils.isNotEmpty(storedCheck) && tryCount >= 0) {
            code = RandomUtil.randomStringWithoutStr(HTCheckConstant.CODE_LENGTH, "0oO1lL");
            storedCheck = industrySalonCheckService.queryByCode(salonId, code);
            tryCount--;
        }

        return (oConvertUtils.isNotEmpty(storedCheck)) ? null : code;
    }

}
